# vPresent is an immersive presentation creation and display application.
# Copyright (C) 2007 by Infiscape Corporation
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

import logging
import traceback

import gui.cluster
import gui.cluster.node
import gui.cluster.display


class SettingsBuilder:
   '''
   This class creates a list of gui.cluster.node.Node objects using the
   information in a util.settings.Settings object. The root of this object
   must have one or more children of its root matching the pattern
   "cluster/node" in order for any gui.cluster.node.Node objects to be created.
   '''
   def __init__(self, settings):
      self.settings = settings
      self.logger   = logging.getLogger('builder.SettingsBuilder')

   def build(self):
      new_cluster = gui.cluster.Cluster()

      for n in self.settings.findall('cluster/node'):
         cur_node = gui.cluster.node.Node(n['name'])

         address = n['address']
         port    = n['port']

         if address is None or port is None:
            self.logger.error("Could not process node %s" % cur_node.getName())
            continue

         cur_node.setAddress(address.strip())

         try:
            cur_node.setPort(int(port.strip()))
         except ValueError:
            traceback.print_exc()

         pipes = n.getChildren('pipes/pipe')

         for p in pipes:
            try:
               cur_node.addPipe(self.buildPipe(p))
            except Exception, ex:
               #self.logger.error(str(ex))
               traceback.print_exc()

         new_cluster.append(cur_node)

      return new_cluster

   def buildPipe(self, pipeSettings):
      pipe = gui.cluster.display.Pipe(pipeSettings['name'])

      try:
         pipe.setScreenID(pipeSettings['screen'].strip())
      except IndexError, ex:
         self.logger.warning("Could not get screen ID for pipe %s" % \
                                pipe.getName())
         traceback.print_exc()

      window = pipeSettings.getChild('window')

      if window is None:
         raise Exception("ERROR: Pipe %s has no window!" % pipe.getName())

      pipe.setWindow(self.buildWindow(window, pipe))

      # The list of supported projector types and the corresponding builder
      # method.
      projector_types = [('fov_projector', self.buildFovProjector)]

      # Figure out which type of projector is specified for this pipe.
      for t in projector_types:
         projector = pipeSettings.getChild(t[0])
         if projector is not None:
            projector_builder = t[1]
            break

      if projector is not None:
         pipe.setProjector(projector_builder(projector))
      else:
         raise Exception("ERROR: Pipe %s has no projector!" % pipe.getName())

      return pipe

   def buildWindow(self, winSettings, pipe):
      window = gui.cluster.display.Window(pipe)

      try:
         width = int(winSettings['width'].strip())
      except:
         traceback.print_exc()
         width = window.getWidth()

      try:
         height = int(winSettings['height'].strip())
      except:
         traceback.print_exc()
         height = window.getHeight()

      try:
         pos_x = int(winSettings['x'].strip())
      except:
         traceback.print_exc()
         pos_x = window.getX()

      try:
         pos_y = int(winSettings['y'].strip())
      except:
         traceback.print_exc()
         pos_y = window.getY()

      try:
         window.setFullScreen(
            self._convertToBool(winSettings['full_screen'].strip())
         )
      except:
         traceback.print_exc()

      try:
         window.setAlwaysOnTop(
            self._convertToBool(winSettings['always_on_top'].strip())
         )
      except:
         traceback.print_exc()

      try:
         window.setStereo(
            self._convertToBool(winSettings['stereo'].strip())
         )
      except:
         traceback.print_exc()

      try:
         window.setHasBorder(
            self._convertToBool(winSettings['border'].strip())
         )
      except:
         traceback.print_exc()

      window.setSize(width, height)
      window.setPosition(pos_x, pos_y)

      return window

   def buildFovProjector(self, projSettings):
      near        = self._convertToFloat(projSettings, 'near')
      far         = self._convertToFloat(projSettings, 'far')
      hfov_left   = self._convertToFloat(projSettings, 'hfov_left')
      hfov_right  = self._convertToFloat(projSettings, 'hfov_right')
      vfov_bottom = self._convertToFloat(projSettings, 'vfov_bottom')
      vfov_top    = self._convertToFloat(projSettings, 'vfov_top')
      heading     = self._convertToFloat(projSettings, 'heading')
      pitch       = self._convertToFloat(projSettings, 'pitch')
      roll        = self._convertToFloat(projSettings, 'roll')

      return gui.cluster.display.FovProjector(near, far, hfov_left, hfov_right,
                                              vfov_bottom, vfov_top, heading,
                                              pitch, roll)

   def _convertToBool(self, strValue):
      return strValue != '0' and strValue.lower() != 'false'

   def _convertToFloat(self, s, key):
      return float(s[key].strip())
